package com.ca.zookeeper.base;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * Author Name: Justice
 * Project Name: zookeeper
 * File Name: ZookeeperBase
 * Package Name: com.ca.zookeeper.base
 * Date: 2020-02-21 14:05
 * Copyright (c) 2020,All Rights Reserved.
 * zookeeper 作为存储型的服务器,主要操作就是增删改查
 */

public class ZookeeperBase {
    // JUC中用于阻塞线程的, 可以在多个线程中进行阻塞
    private static CountDownLatch countDownLatch = new CountDownLatch(1);

    public static void main(String[] args) throws IOException, InterruptedException, KeeperException {
        // 连接zookeeper

        //  参数1-zookeeper的地址, 参数2-超时时间, 参数3-监听器
        // 因为zookeeper连接是需要时间的, 所有zookeeper使用的是异步的方式连接, 所以我们需要一个回调的接口对象来知道连接结果
        ZooKeeper zooKeeper = new ZooKeeper(AddressUtil.ADDRESS, 5000, new Watcher() {
            // 当连接成功后会执行当前方法,在此处我们放行即可
            @Override
            public void process(WatchedEvent event) {
                // 事件类型
                Event.EventType type = event.getType();
                // 事件状态
                Event.KeeperState state = event.getState();
                // 判断是否连接成功
                if (state == Event.KeeperState.SyncConnected) {
                    if (type == Event.EventType.None) {
                        System.out.println("建立连接成功");
                        // 放行
                        countDownLatch.countDown();
                    }
                }
            }
        });
        // 因为上面的代码是异步的, 所以到这里的时候对象可能还没有初始化完成, 所以无法使用, 所以我们需要等待初始化完成
        // 因为我们不知道什么时候能初始化完成, 所以不知道睡多久, 所以最好的办法是什么时间完成什么时间直接醒
        countDownLatch.await();

        // 通过api进行增删改查操作

        // path：节点创建的路径
        // data[] ：初始内容的字节数组
        // acl ：权限控制策略
        // createMode：节点类型：
        // EPHEMERAL 临时节点
        // EPHEMERAL_SEQUENTIAL 临时顺序节点
        // PERSISTENT 持久节点
        // PERSISTENT_SEQUENTIAL 持久顺序节点
        // cb：异步回调函数，用于节点创建完毕后回调，需要实现StringCallbacl接口，重写processResult方法
        // ctx：在回调方法执行时，传递一个上下文信息对象
        // 创建结点
        //String path = zooKeeper.create(
        //        "/online04",
        //        "hello world".getBytes(),
        //        ZooDefs.Ids.OPEN_ACL_UNSAFE,
        //        CreateMode.PERSISTENT);
        //System.out.println(path);

        // 创建节点,zookeeper不允许在父目录不存在的情况下创建子目录,也就是不允许递归创建
        // String path = zooKeeper.create("/testonline03/test", "hello java".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        // System.err.println(path);

        // 创立子结点
        //String path = zooKeeper.create("/online04/20200108",
        //        "This is Jack".getBytes(),
        //        ZooDefs.Ids.OPEN_ACL_UNSAFE,
        //        CreateMode.PERSISTENT);
        //System.out.println(path);

        // 读取父结点的数据
//        path：数据节点路径
//        watcher：注册Watcher，如果子节点发生变化，那么就通知客户端
//        cb：异步回调函数
//        ctx：传递上下文信息对象
//        byte[] data = zooKeeper.getData("/online04", false, null);
//        System.out.println(new String(data));

        // 获取子结点的数据, 首先获取所有的子节点
        //List<String> childrenList = zooKeeper.getChildren("/online04", false);
        //// 遍历拿到子结点的路径
        // for (String children : childrenList) {
        //     byte[] data = zooKeeper.getData("/online04/" + children, false, null);
        //     System.out.println(children + "----->" + new String(data));
        // }

        // 修改数据, version代表乐观锁的版本号, 代表要求当前数据的版本必须和version保持一致才可以更新, -1代表忽略版本号
        //Stat stat = zooKeeper.setData("/online04/20200108", "This is Rose".getBytes(), -1);
        //System.out.println(stat);

        // 删除节点
        // path：数据节点路径
        // version：数据节点的版本
        // cb：异步回调函数
        // crx：传递上下文信息对象
        // zooKeeper.delete("/online04", 0);

        // 判断节点是否存在, 如果返回的是null, 代表不存在
        Stat stat = zooKeeper.exists("/online03", false);
        System.out.println(stat);
    }
}
